/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package VoiceIdent;

import edu.cmu.sphinx.frontend.DoubleData;
import java.io.Serializable;
import java.util.ArrayList;
/**
 *
 * @author JArik
 */
public class VoiceData implements Serializable{

    private ArrayList<MfccVector> data;
    transient private int maxSize;
    transient private int drift=0;
    private int id;
    private int userId;
    private String userName;
    
    public VoiceData()
    {
        data = new ArrayList<MfccVector>();
    }

    public VoiceData(int size)
    {
        data = new ArrayList<MfccVector>();
        maxSize = size;
    }
    public VoiceData(int size, int dr)
    {
        data = new ArrayList<MfccVector>();
        maxSize = size;
        drift = dr;
    }

    public ArrayList<MfccVector> getData()
    {
        return data;
    }
    public boolean isFilled()
    {
        return data.size() == maxSize && drift <=0;
    }
      public int getPercFilled()
    {
        return Math.round(((float)data.size()/(float)maxSize)*100);
    }
    public int getSize()
    {
        return data.size();
    }
    public void add(MfccVector v)
    {
        data.add(v);
    }
    public MfccVector get(int ind)
    {
        return data.get(ind);
    }
    public void push(DoubleData dat)
    {
        MfccVector vector = new MfccVector();
        vector.addVoiceFeatures(dat.getValues());
        
        if(data.size() < maxSize)
          data.add(vector);
        else
        {
          data.add(0, vector);
          data.remove(maxSize);
          drift--;
        }
    }

    // quantization
    public VoiceData quantize(int centrNum) throws Exception
    {
        VoiceData codebook = new VoiceData(centrNum);
        Centroid centroid = new Centroid(this);
        
        ArrayList<Centroid> cList = estimateCodeBook(centroid, centrNum);

        fetchToCodeBook(cList, codebook);
        
        return codebook;
    }
    private void fetchToCodeBook(ArrayList<Centroid> cList, VoiceData cb)
    {
        for(int i=0; i<cList.size(); i++)
            cb.add((MfccVector) cList.get(i).clone());
        
    }
    private ArrayList<Centroid> estimateCodeBook(Centroid cb, int entryNum) throws Exception
    {
        ArrayList<Centroid> ctrList = new ArrayList();
        cb.recalcSector();
        cb.recalcPosition();
        ctrList.add(cb);
        Centroid tempCentr;
        while(ctrList.size() < entryNum)
        {
           int listSize = ctrList.size();
           System.out.print(" | " + listSize );
           for(int c=0; c < listSize; c++)
           {
               tempCentr = ctrList.get(c);
               tempCentr = splitCentroid(tempCentr, 0.005);
               for(int i=0; i<10; i++)
               {
                 // recalc sectors
                 tempCentr.getLeftCentroid().recalcSector();
                 tempCentr.getRightCentroid().recalcSector();
                 // recalc positions
                 tempCentr.getLeftCentroid().recalcPosition();
                 tempCentr.getRightCentroid().recalcPosition();
               }
               ctrList.remove(tempCentr);
               ctrList.add(tempCentr.getLeftCentroid());
               ctrList.add(tempCentr.getRightCentroid());
           }
           
        }
        System.out.println(" List Size: " + ctrList.size());
        return ctrList;
    }
    private Centroid splitCentroid(Centroid centr,double delta)
    {
        Centroid centr1 = new Centroid(centr);
        Centroid centr2 = new Centroid(centr);
        centr.setLeftCentroid(centr1);
        centr.setRightCentroid(centr2);
        // move each element in vector
        for(int i=0; i < centr.size(); i++)
        {
            centr1.add(centr.get(i)-delta);
            centr2.add(centr.get(i)+delta);
        }
        return centr;
    }

    public double estimateError(VoiceData identData) throws Exception
    {
        double error = 0;
        ArrayList<MfccVector> iData = identData.getData();
        for(int i=0; i<iData.size(); i++)
            for(int y=0; y<data.size(); y++)
            {
                error += iData.get(i).getDistance(data.get(y));
            }
        return error;
    }
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }


    public String toString()
    {
        return userName;
    }

}
